package indi.zhifa.study2024.consigntest.logic.busy.consign.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import indi.zhifa.core.common.util.CommonUtil;
import indi.zhifa.study2024.consigntest.billNo.BillNoUtil;
import indi.zhifa.study2024.consigntest.gen.busy.consign.po.GenConsignEntity;
import indi.zhifa.study2024.consigntest.gen.busy.consign.po.GenConsignHeaderEntity;
import indi.zhifa.study2024.consigntest.gen.busy.consign.po.GenConsignNewEntity;
import indi.zhifa.study2024.consigntest.gen.busy.consign.service.IGenConsignDbService;
import indi.zhifa.study2024.consigntest.gen.busy.consign.service.IGenConsignHeaderDbService;
import indi.zhifa.study2024.consigntest.gen.busy.consign.service.IGenConsignNewDbService;
import indi.zhifa.study2024.consigntest.gen.busy.define.po.*;
import indi.zhifa.study2024.consigntest.gen.busy.define.service.*;
import indi.zhifa.study2024.consigntest.logic.busy.consign.IConsignService;
import indi.zhifa.study2024.consigntest.logic.busy.consign.entity.mapperIn.ConsignMapperIn;
import indi.zhifa.study2024.consigntest.logic.busy.consign.entity.mapperOut.ConsignMapperOut;
import indi.zhifa.study2024.consigntest.logic.busy.consign.entity.request.ConsignPageRequest;
import indi.zhifa.study2024.consigntest.logic.busy.consign.mapper.ConsignMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.support.TransactionTemplate;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
@RequiredArgsConstructor
@Component
public class ConsignServiceImpl implements IConsignService {

    final ConsignMapper mConsignMapper;

    final IGenEnterpriseDbService mEnterpriseDbService;
    final IGenSalesManDbService mSalesManDbService;
    final IGenCustomerDbService mCustomerDbService;
    final IGenItemDbService mItemDbService;
    final IGenConsignDbService mConsignDbService;
    final IGenConsignHeaderDbService mConsignHeaderDbService;
    final BillNoUtil mBillNoUtil;
    final PlatformTransactionManager mTransactionManager;

    final IGenConsignNewDbService mConsignNewDbService;
    final IGenItemNewDbService mItemNewDbService;


    @Override
    public void initTestData() {
        final int ENP_CNT = 10;
        final int SALES_CNT_MIN = 5;
        final int SALES_CNT_MAX = 20;
        final int CUSTOMER_CNT_MIN = 20;
        final int CUSTOMER_CNT_MAX = 50;
        final int ITEM_CNT_MIN = 2000;
        final int ITEM_CNT_MAX = 10000;

        final long ITEM_COST_MIN = 500;
        final long ITEM_COST_MAX = 19800;

        final int ITEM_PROFIT_MIN = 10;
        final int ITEM_PROFIT_MAX = 50;

        // 每个门店售卖某个商品的概率
        final int CUSTOMER_ITEM_SELECT_PERCENT = 30;
        // 每个售货员当天来特定门店的概率
        final int CUSTOMER_SALES_SELECT_PERCENT = 15;
        // 售货员来该门店，每样商品送货的概率，万分制
        // 这个概率远小于真实情况，只不过我为了导入快点。正常概率，我们认为一周送2次货，拍2800更合适
        final int ITEM_SALES_SELECT_PERCENT = 250;

        final int ITEM_SALES_CNT_MIN = 10;
        final int ITEM_SALES_CNT_MAX = 1000;
        final String DAY_BEGIN = "2018-01-01";
        final String DAY_END = "2024-12-31";

        // 清空测试数据
        mEnterpriseDbService.clearTest();
        mSalesManDbService.clearTest();
        mCustomerDbService.clearTest();
        mItemDbService.clearTest();
        mConsignDbService.clearTest();
        mConsignHeaderDbService.clearTest();


        // 生成企业
        List<GenEnterpriseEntity> entList = new ArrayList<>();
        for(int i = 1; i <= ENP_CNT; i++) {
            GenEnterpriseEntity enterpriseEntity = new GenEnterpriseEntity();
            enterpriseEntity.createInit();
            enterpriseEntity.setCode(String.format("enp_%03d", i));
            enterpriseEntity.setName(String.format("enp_%03d", i));
            enterpriseEntity.setTestData(true);
            entList.add(enterpriseEntity);
        }

        mEnterpriseDbService.saveBatch(entList);
        Map<Long,List<GenSalesManEntity>> salseManMap = new HashMap<>();
        Map<Long,List<GenCustomerEntity>> customerMap = new HashMap<>();
        Map<Long,List<GenItemEntity>> itemMap = new HashMap<>();
        Map<Long,List<GenItemEntity>> customerItemMap = new HashMap<>();

        // 循环每个企业，用局部变量，节省内存
        for(GenEnterpriseEntity enterpriseEntity : entList) {
            // 为每个企业生成售货员
            int salesCnt = RandomUtil.randomInt(SALES_CNT_MIN, SALES_CNT_MAX);
            List<GenSalesManEntity> salesManEntityList = new ArrayList<>();
            for(int i = 1; i <= salesCnt; i++) {
                GenSalesManEntity salesManEntity = new GenSalesManEntity();
                salesManEntity.createInit();
                salesManEntity.setName(String.format("%s_sales_%03d", enterpriseEntity.getName(),i));
                salesManEntity.setTestData(true);
                salesManEntity.setEnpId(enterpriseEntity.getId());
                salesManEntity.setEnpCode(enterpriseEntity.getCode());
                salesManEntityList.add(salesManEntity);
            }
            mSalesManDbService.saveBatch(salesManEntityList);
            salseManMap.put(enterpriseEntity.getId(), salesManEntityList);
            // 为每个企业生成门店
            int customerCnt = RandomUtil.randomInt(CUSTOMER_CNT_MIN, CUSTOMER_CNT_MAX);
            List<GenCustomerEntity> customerEntityList = new ArrayList<>();
            for(int i = 1; i <= customerCnt; i++) {
                GenCustomerEntity customerEntity = new GenCustomerEntity();
                customerEntity.createInit();
                customerEntity.setName(String.format("%s_customer_%03d", enterpriseEntity.getName(),i));
                customerEntity.setTestData(true);
                customerEntity.setEnpId(enterpriseEntity.getId());
                customerEntity.setEnpCode(enterpriseEntity.getCode());
                customerEntityList.add(customerEntity);
            }
            mCustomerDbService.saveBatch(customerEntityList);
            customerMap.put(enterpriseEntity.getId(), customerEntityList);
            // 为每个企业生成商品
            int itemCnt = RandomUtil.randomInt(ITEM_CNT_MIN, ITEM_CNT_MAX);
            List<GenItemEntity> itemEntityList = new ArrayList<>();
            for(int i=1;i<=itemCnt;i++){
                GenItemEntity itemEntity = new GenItemEntity();
                itemEntity.createInit();
                itemEntity.setRelId(String.valueOf(itemEntity.getId()));
                itemEntity.setName(String.format("%s_item_%03d", enterpriseEntity.getName(),i));
                long cost = RandomUtil.randomLong(ITEM_COST_MIN, ITEM_COST_MAX);
                itemEntity.setCost(cost);
                itemEntity.setTestData(true);
                itemEntity.setEnpId(enterpriseEntity.getId());
                itemEntity.setEnpCode(enterpriseEntity.getCode());
                itemEntityList.add(itemEntity);
            }
            mItemDbService.saveBatch(itemEntityList);
            itemMap.put(enterpriseEntity.getId(), itemEntityList);

            // 确定每个门店的商品列表
            for(GenCustomerEntity customerEntity : customerEntityList) {
                List<GenItemEntity> itemList = new ArrayList<>();
                for(GenItemEntity itemEntity : itemEntityList) {
                    int rd =RandomUtil.randomInt(0,100);
                    if(rd < CUSTOMER_ITEM_SELECT_PERCENT){
                        itemList.add(itemEntity);
                    }
                }
                customerItemMap.put(customerEntity.getId(), itemList);
            }
        }

        LocalDate startDate = LocalDate.parse(DAY_BEGIN);
        LocalDate endDate = LocalDate.parse(DAY_END);

        final ExecutorService executorService = Executors.newFixedThreadPool(20);

        while (!startDate.isAfter(endDate)) {
            log.info("==================>>导入日期"+startDate+"====================");
            // 遍历每个企业
            for(GenEnterpriseEntity enterpriseEntity : entList) {
                List<GenSalesManEntity> salesManEntityList = salseManMap.get(enterpriseEntity.getId());
                List<GenCustomerEntity> customerEntityList = customerMap.get(enterpriseEntity.getId());
                List<GenConsignHeaderEntity> consignHeaderEntityList = new ArrayList<>();
                List<GenConsignEntity> consignEntityList = new ArrayList<>();

                log.info("导入企业"+enterpriseEntity.getName());
                // 遍历旗下所有销售
                for(GenSalesManEntity salesManEntity : salesManEntityList) {
                    // 遍历旗下所有门店
                    for(GenCustomerEntity customerEntity : customerEntityList) {
                       int rd = RandomUtil.randomInt(0,100);
                       // 售货员不来该门店
                       if(rd >= CUSTOMER_SALES_SELECT_PERCENT){
                           continue;
                       }

                       //创建头表
                        GenConsignHeaderEntity consignHeaderEntity = new GenConsignHeaderEntity();
                        consignHeaderEntity.createInit();
                        consignHeaderEntity.setEnpId(enterpriseEntity.getId());
                        consignHeaderEntity.setEnpCode(enterpriseEntity.getCode());
                        consignHeaderEntity.setBillNo(mBillNoUtil.getBillNo("csn"));

                        int hour = RandomUtil.randomInt(0,24);
                        int minute = RandomUtil.randomInt(0,59);
                        int second = RandomUtil.randomInt(0,59);
                        LocalDateTime billTime = startDate.atTime(hour, minute, second);
                        long billTimeKey = CommonUtil.LocalDateTimeToSecond(billTime);
                        String billTimeStr = LocalDateTimeUtil.formatNormal(billTime);

                        consignHeaderEntity.setBillTime(billTime);
                        consignHeaderEntity.setBillTimeKey(billTimeKey);
                        consignHeaderEntity.setBillTimeStr(billTimeStr);

                        consignHeaderEntity.setCustomerId(customerEntity.getId());
                        consignHeaderEntity.setCustomerName(customerEntity.getName());
                        consignHeaderEntity.setSalesId(salesManEntity.getId());
                        consignHeaderEntity.setSalesName(salesManEntity.getName());

                        consignHeaderEntity.setDescription(billTimeStr+" "+customerEntity.getName()+" "+salesManEntity.getName());
                        consignHeaderEntity.setTestData(true);
                        consignHeaderEntityList.add(consignHeaderEntity);

                       List<GenItemEntity> itemEntityList = customerItemMap.get(customerEntity.getId());
                       for(GenItemEntity itemEntity : itemEntityList) {
                           rd = RandomUtil.randomInt(0,10000);
                           if(rd >= ITEM_SALES_SELECT_PERCENT){
                               continue;
                           }
                           int saleCnt = RandomUtil.randomInt(ITEM_SALES_CNT_MIN,ITEM_SALES_CNT_MAX);
                           GenConsignEntity consignEntity = new GenConsignEntity();
                           consignEntity.createInit();
                           consignEntity.setEnpId(enterpriseEntity.getId());
                           consignEntity.setEnpCode(enterpriseEntity.getCode());
                           consignEntity.setCustomerId(customerEntity.getId());
                           consignEntity.setCustomerName(customerEntity.getName());
                           consignEntity.setItemId(itemEntity.getId());
                           consignEntity.setItemStrId(String.valueOf(itemEntity.getId()));
                           consignEntity.setItemName(itemEntity.getName());
                           consignEntity.setItemCnt(saleCnt);
                           consignEntity.setSalesId(salesManEntity.getId());
                           consignEntity.setSalesName(salesManEntity.getName());

                           consignEntity.setBillTime(billTime);
                           consignEntity.setBillTimeKey(billTimeKey);
                           consignEntity.setHeaderId(consignHeaderEntity.getId());
                           consignEntity.setBillNo(consignHeaderEntity.getBillNo());

                           int profitPercent = RandomUtil.randomInt(ITEM_PROFIT_MIN,ITEM_PROFIT_MAX);
                           long cost = (long)(itemEntity.getCost() * (1 + profitPercent/100.0));
                           consignEntity.setPrice(cost);
                           consignEntity.setTestData(true);
                           consignEntityList.add(consignEntity);
                       }
                    }
                }
                // 多线程反而更慢，因为插入的顺序问题
//                executorService.submit(()->{
//                    TransactionTemplate template = new TransactionTemplate(mTransactionManager);
//                    template.execute(status ->{
//                        mConsignHeaderDbService.saveBatch(consignHeaderEntityList);
//                        mConsignDbService.saveBatch(consignEntityList);
//                        return true;
//                    });
//                });

                TransactionTemplate template = new TransactionTemplate(mTransactionManager);
                template.execute(status ->{
                    mConsignHeaderDbService.saveBatch(consignHeaderEntityList);
                    mConsignDbService.saveBatch(consignEntityList);
                    return true;
                });

                log.info("本轮销售单已提交导入");
            }
            startDate = startDate.plusDays(1l);
        }
    }

    @Override
    public void syncNewTable() {
        // 查出所有企业
        List<GenEnterpriseEntity> enterpriseEntities = mEnterpriseDbService.list();

        for(GenEnterpriseEntity enterpriseEntity : enterpriseEntities) {

            log.info("开始导入"+enterpriseEntity.getName()+"数据");

            List<GenItemEntity> itemEntityList = mItemDbService.listByEnpId(enterpriseEntity.getId());
            List<GenItemNewEntity> itemNewEntityList = new ArrayList<>();

            for(GenItemEntity itemEntity : itemEntityList) {
                GenItemNewEntity itemNewEntity = new GenItemNewEntity();
                itemNewEntity.createInit();
                itemNewEntity.setEnpId(itemEntity.getId());
                itemNewEntity.setEnpCode(itemEntity.getEnpCode());
                itemNewEntity.setId(itemEntity.getId());
                itemNewEntity.setName(itemEntity.getName());
                itemNewEntity.setCost(itemEntity.getCost());
                itemNewEntity.setTestData(true);
                itemNewEntityList.add(itemNewEntity);
            }

            TransactionTemplate template = new TransactionTemplate(mTransactionManager);
            template.execute(status ->{
                mItemNewDbService.saveBatch(itemNewEntityList);
                return true;
            });
            log.info("导入商品完成");

            final String DAY_BEGIN = "2018-01-01";
            final String DAY_END = "2024-12-31";


            LocalDate startDate = LocalDate.parse(DAY_BEGIN);
            LocalDate endDate = LocalDate.parse(DAY_END);

            while (!startDate.isAfter(endDate)) {

                log.info("导入"+startDate+"的销售单数据");

                LocalDateTime billTimeBeg = startDate.atTime(0, 0, 0);
                LocalDateTime billTimeEnd = startDate.atTime(23, 59, 59);

                long billTimeKeyBeg = CommonUtil.LocalDateTimeToSecond(billTimeBeg);
                long billTimeKeyEnd = CommonUtil.LocalDateTimeToSecond(billTimeEnd);

                List<GenConsignEntity> consignEntityList = mConsignDbService.findAll(enterpriseEntity.getId(),billTimeKeyBeg,billTimeKeyEnd);
                List<GenConsignNewEntity> consignNewEntityList = new ArrayList<>();

                for(GenConsignEntity consignEntity : consignEntityList) {
                    GenConsignNewEntity consignNewEntity = new GenConsignNewEntity();
                    consignNewEntity.createInit();
                    consignNewEntity.setId(consignEntity.getId());
                    consignNewEntity.setEnpId(consignEntity.getEnpId());
                    consignNewEntity.setHeaderId(consignEntity.getHeaderId());
                    consignNewEntity.setBillTimeKey(consignEntity.getBillTimeKey());
                    consignNewEntity.setItemId(consignEntity.getItemId());
                    consignNewEntity.setItemName(consignEntity.getItemName());
                    consignNewEntity.setItemCnt(consignEntity.getItemCnt());
                    consignNewEntity.setPrice(consignEntity.getPrice());
                    consignNewEntity.setDescription(consignEntity.getDescription());
                    consignNewEntity.setTestData(true);
                    consignNewEntityList.add(consignNewEntity);
                }
                consignNewEntityList.sort(Comparator.comparing(GenConsignNewEntity::getHeaderId));

                template = new TransactionTemplate(mTransactionManager);
                template.execute(status -> {
                    mConsignNewDbService.saveBatch(consignNewEntityList);
                    return true;
                });

                log.info(startDate+"的销售单数据导入完成");

                startDate = startDate.plusDays(1l);
            }
        }
    }

    @Override
    public Page<ConsignMapperOut> pageGroupByItemId(ConsignPageRequest pConsignPageRequest) {
        Page<ConsignMapperOut> pageCfg = new Page<>(pConsignPageRequest.getCurrent(),pConsignPageRequest.getSize());
        ConsignMapperIn consignMapperIn = pConsignPageRequest.toMapperIn();
        long curTime = System.currentTimeMillis();
        Page<ConsignMapperOut> consignMapperOutPage = mConsignMapper.page(pageCfg, consignMapperIn);
        long endTime = System.currentTimeMillis();
        log.info("cost time "+(endTime - curTime)/1000.0 + "s");
        return consignMapperOutPage;
    }
}
